import Vue,{CreateElement,VNode,VueConstructor,PropOptions} from 'vue';
import {throttle} from '../../../util/common';
import {SizeObj,ResizeObserverType} from '../../../../types';
const hasObserver=typeof ResizeObserver!=='undefined';

interface ResizeObserverVue extends Vue{
	url:string|void;
	defaultView:Window;
	emitEvent():void;
}
/**
 * 监听大小组件
 * @author 唐国雄
 * @date 2022/5/15
 * 属性----------------------
 * :throttle	节流时间
 * :type		兼容实现的类型(scroll性能更高), ResizeObserverType
 * 事件----------------------
 * @resize		大小变化, SizeObj
 * 插槽----------------------
 * #default		内容, SizeObj
 */
export default (Vue as VueConstructor<ResizeObserverVue>).extend({
	name:'ResizeObserver',
	props:{
		throttle:{
			type:Number,
			default:100,
		},
		type:{
			type:String,
			default:'scroll',
		} as PropOptions<ResizeObserverType>,
	},
	data(){
		const data={
			size:{width:0,height:0} as SizeObj,
		};
		if(!hasObserver&&this.type==='object'){
			return {
				...data,
				url:null as null|string,
			};
		}
		return data;
	},
	created(){
		//region 发射 resize 事件
		const getSizeObject=() => {
			const {offsetWidth,offsetHeight}=(this.$el as HTMLElement);
			const size=this.size;
			if(size.width!==offsetWidth||size.height!==offsetHeight){
				const newSize:SizeObj={
					width:offsetWidth,
					height:offsetHeight,
				};
				this.size=newSize;
				this.$emit('resize',newSize);
			}
		};
		if(hasObserver||this.type==='object'){
			this.emitEvent=throttle(getSizeObject,this.throttle||undefined);
		}else{
			this.emitEvent=throttle(() => {
				getSizeObject();
				const refs=this.$refs as {expand:HTMLElement,shrink:HTMLElement};
				refs.expand.scrollLeft=refs.shrink.scrollLeft=1e8;
				refs.expand.scrollTop=refs.shrink.scrollTop=1e8;
			},this.throttle||undefined);
		}
		//endregion
	},
	mounted(){
		this.$nextTick(function(){
			if(hasObserver){
				//region 现代浏览器支持 ResizeObserver
				const observer=new ResizeObserver(this.emitEvent);
				observer.observe(this.$el,{box:'border-box'});
				this.$once('hook:beforeDestroy',() => {
					observer.disconnect();
				});
				//endregion
			}else if(this.type==='object'){
				this.url='about:blank';
				this.$once('hook:beforeDestroy',() => {
					this.$_pf_cleanFn();
				});
			}else{
				this.emitEvent();
			}
		});
	},
	methods:{
		//region 添加 Object 事件监听
		$_pf_loadFn():void{
			this.$_pf_cleanFn();
			const contentDocument=(this.$refs.object as HTMLObjectElement).contentDocument;
			if(contentDocument){
				this.defaultView=contentDocument.defaultView!;
				this.defaultView.addEventListener('resize',this.emitEvent,{passive:true});
			}
			this.emitEvent();
		},
		//endregion
		//region 清理 object 事件监听
		$_pf_cleanFn():void{
			if(this.defaultView){
				this.defaultView.removeEventListener('resize',this.emitEvent);
			}
		},
		//endregion
	},
	render(h:CreateElement):VNode{
		const slot=this.$scopedSlots.default;
		const content=this.$slots.default||(slot&&slot(this.size));
		return h('div',{
			staticClass:'lms-ResizeObserver',
		},
		hasObserver
			?content
			:this.type==='scroll'
			//region scroll 模式
				?[
					h('div',{
						ref:'expand',
						staticClass:'lms-ResizeObserver_expand',
						on:{
							'&scroll':this.emitEvent,
						}
					},[h('div')]),
					h('div',{
						ref:'shrink',
						staticClass:'lms-ResizeObserver_shrink',
						on:{
							'&scroll':this.emitEvent,
						}
					},[h('div')]),
					content,
				]
			//endregion
			//region object 模式
				:[
					h('object',{
						ref:'object',
						staticClass:'lms-ResizeObserver_object',
						attrs:{
							tabindex:-1,
							type:'text/html',
							data:this.url,
							'aria-hidden':'true',
						},
						on:{
							load:this.$_pf_loadFn,
						}
					}),
					content,
				]
			//endregion
		);
	}
});
